Een PSR-4 autoloader implementeren
Home

Een PSR-4 autoloader implementeren

Een PSR-4 autoloader implementeren

Een voorbeeld hoe je een PSR-4 autoloader implementeert

Probleem

We willen klassenbestanden automatisch kunnen laden wanneer we een instantie aanmaken met behulp van het new keyword. Als voorbeeld gaan we een bibliotheek met de naam Helpers implementeren. Deze bibliotheek bevat één klasse met de naam Hello die een string echoot. We willen een instantie van die klasse kunnen maken zonder dat we het Hello.php bestand moeten includen. We willen dat de instructie $hello = new \ModernWays\Helpers\Hello(); opzich volstaat. De apllicatie moet zelf maar uitzoeken in welk bestand die klasse staat en het bestand laden.

Design

Mappenstructuur

We volgen de afspraak van Composer voor de mappenstructuur.

psr-4 autoloader implementeren mappenstructuur
psr-4 autoloader implementeren mappenstructuur
  1. De rootmap voor de bibliotheken is vendor.
  2. In deze rootmap maken een submap voor elke vendor. Een vendor is een bedrijf of organisatie die bibliotheken maakt en ter beschikking van derden stelt.Ons bedrijf heet Modern Ways.
  3. In de vendor map maken we een submap voor elke bibliotheek. Voor ons voorbeeld is dat een Helpers bibliotheek. Dus de maken een submap met de naam Helpers. Let erop dat de namen van de mappen moeten overeenkomen met de namespaces.
  4. Het is de gewoonte om de klassenbestanden in een src submap in de bibliotheekmap te plaatsen.
  5. In de scr map van de bibliotheekmap plaatsen we de klassenbestanden. De namen van die bestanden moeten overeenkomen met de klassennaam en is hoofdlettergevoelig.
  6. In de bibliotheek map plaatsen we het autoload.php bestand dat we includen in de index pagina van de website.

Oplossing

De Hello klasse

De autoloader veronderstelt een prefixnamespace die wordt vervangen door het fysieke pad. Dat wordt in het begin van de autoloader uitgevoerd:

// project-specific namespace prefix
$prefix = 'PlopperDePlop\\DeKabouter\\';
// base directory for the namespace prefix
$base_dir = __DIR__ . '/src/';

Dus de Hello klasse ziet er als volgt uit:

<?php
/**
 * Created by Jef Inghelbrecht.
 * User: jefin
 * Date: 13/12/2015
 * Time: 12:36
 */
namespace PlopperDePlop\DeKabouter;

class Hello
{
    // constructor wordt uitgevoerd met 
    // het new keyword
    public function __construct()
    {
        echo 'Hello World!';
    }
}

We maken nog een tweede klassenbestand met de naam HelloAgain.php.

<?php
/**
 * Created by PhpStorm.
 * User: jefin
 * Date: 14/12/2015
 * Time: 21:36
 */
namespace PlopperDePlop\DeKabouter;

class HelloAgain
{
    // constructor wordt uitgevoerd met
    // het new keyword
    public function __construct()
    {
        echo 'Hello again World!';
    }
}

Het autoload bestand

Het autoload bestand moet in de map staan waaraan de namespaceprefix is gelijkgesteld. In ons voorbeeld is dat __DIR__ . '/src/'. Het enige wat je moet doen is de namespaceprefix aanpassen aan de namespace van je eigen bibliotheek.

<?php
/* An example of a project-specific implementation.
* bron: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md
* After registering this autoload function with SPL, the following line
* would cause the function to attempt to load the \Foo\Bar\Baz\Qux class
* from /path/to/project/src/Baz/Qux.php:
*
* new \Foo\Bar\Baz\Qux;
*
* @param string $class The fully qualified class name.
* @return void
*/
spl_autoload_register(function ($class) {
    // project-specific namespace prefix
    $prefix = 'PlopperDePlop\\DeKabouter\\';
    // base directory for the namespace prefix
    $base_dir = __DIR__ . '/src/';
    // echo $base_dir;
    // does the class use the namespace prefix?
    $len = strlen($prefix);
    if (strncmp($prefix, $class, $len) !== 0) {
        // no, move to the next registered autoloader
        return;
    }
    // get the relative class name
    $relative_class = substr($class, $len);
    // replace the namespace prefix with the base directory,
    //  separators with directory separators in the relative class name, append // with .php
    $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
    // if the file exists, require it
    if (file_exists($file)) {
        require $file;
    }
});

De klassen gebruiken

Maak een bestand in de rootmap van je website met de naam autoloader-test.php.

<?php
/**
* Created by Jef Inghelbrecht.
* User: jefin
* Date: 14/12/2015
* Time: 21:34
*/
include ('vendor/modernways/helpers/autoload.php');

$hello = new PlopperDePlop\DeKabouter\Hello();
$helloAgain = new \PlopperDePlop\DeKabouter\HelloAgain();

Zonder de autoload, had ik hier twee keer include moeten gebruiken om de twee klassenbestand Hello.php en HelloAgain.php te laden vooraleer de klassen, die erin gedefinieerd werden, te kunnen gebruiken.

JI
2015-12-14 22:11:08